﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Speech.Recognition;

namespace CodeTalk.CTSpeechCommands
{
    class NewSymbol : SpeechCommand
    {
        internal override GrammarBuilder GrammarBld(Context context, Context[] libraries)
        {
            Choices c = new Choices();
            for (int i = 0; i < (int)SymbolCategory.nSymbolCategories; i++)
                c.Add(new SemanticResultValue(((SymbolCategory)i).ToString().ToLowerInvariant(), i));

            GrammarBuilder gb = new GrammarBuilder("new");
            gb.Append(new SemanticResultKey("SymbolCategory", c));
            gb.AppendDictation();
            return gb;
        }

        public override string Name
        {
            get { return "New symbol"; }
        }

        public override string Description
        {
            get { return Name; }
        }

        public override string GetAlternativesFeedback(string recognizedText, SemanticValue semValue)
        {
            return recognizedText;
        }

        internal override bool CanSpokenFormMatch(string spokenForm)
        {
            for (int i = 0; i < (int)SymbolCategory.nSymbolCategories; i++)
            {
                if (spokenForm.StartsWith("new " + ((SymbolCategory)i).ToString() + " "))
                    return true;
            }
            return false;
        }

        internal override object Execute(SpeechMode callingMode, string recognizedText, SemanticValue semValue)
        {
            try
            {
                int categoryIndex = (int)semValue["SymbolCategory"].Value;
                SymbolCategory category = (SymbolCategory)categoryIndex;
                int categoryLength = category.ToString().Length;
                if (recognizedText.StartsWith("new "))
                {
                    string variableText = recognizedText.Substring(4 + categoryLength + 1);
                    string errMsg = "";
                    string writtenForm = TextUtilz.MakeVariabelName(variableText, category);
                    uint id = callingMode.CurrentContext.CreateNewSymbol(writtenForm, variableText, category, callingMode, ref errMsg);

                    if (id == 0)
                    {
                        callingMode.CurrentGuiHandler.SetErrorFeedback(errMsg);
                        return null;
                    }

                    callingMode.CurrentGuiHandler.RefreshSymbolView();
                    callingMode.RecompileGrammar();

                    if (category == SymbolCategory.Function)
                        writtenForm += "{)}{LEFT}{(}";
                    else if (category == SymbolCategory.Type)
                        writtenForm += " ";

                    callingMode.CurrentOutputHandler.SendKeys(writtenForm);

                    callingMode.CurrentGuiHandler.SetPrimaryFeedback("New " + category.ToString().ToLowerInvariant() + ": " + writtenForm + " (" + variableText + ")");
                    return id;
                }
                return null;
            }
            catch (Exception ex)
            {
                callingMode.CurrentGuiHandler.SetErrorFeedback("Internal error in NewSymbol: " + ex);
                return null;
            }
        }

        internal override void Undo(SpeechMode callingMode, string recognizedText, SemanticValue semValue, object undoObject)
        {
            if (undoObject != null)
            {
                uint id = (uint)undoObject;
                CodeSymbol cs = callingMode.CurrentContext.GetSymbolWithID(id);
                SymbolCategory category = cs.Category;
                if (category == SymbolCategory.Function)
                    callingMode.CurrentOutputHandler.SendKeys("^z^z");
                else if (category == SymbolCategory.Type)
                    callingMode.CurrentOutputHandler.SendKeys("^z");
                else
                {
                    for (int i = 0; i < cs.WrittenForm.Length; i++)
                        callingMode.CurrentOutputHandler.SendKeys("{BS}");
                }

                callingMode.CurrentContext.DeleteSymbolWithID(id);
                callingMode.CurrentGuiHandler.RefreshSymbolView();
            }
        }
    }
}
